import copy
import re
from typing import Dict
import math
from vnpy.event import Event, EventEngine
from vnpy.trader.engine import MainEngine
from vnpy.trader.setting import SETTINGS
from vnpy.trader.ui import QtCore, QtGui, QtWidgets
from vnpy.trader.ui.widget import (
    BaseCell,
    EnumCell,
    MsgCell,
    TimeCell,
    sInfoDialog,
    ConfirmDialog,
    BaseMonitor
)
from vnpy.trader.event import (
    EVENT_LOG,
    EVENT_POPUP,
    EVENT_CTA_LOG,
)
from ..base import (
    APP_NAME,
    EVENT_CTA_STOPORDER,
    EVENT_CTA_STRATEGY
)
from ..engine import CtaEngine
from .rollover import RolloverTool

class CtaManager(QtWidgets.QWidget) :
    signal_log: QtCore.Signal = QtCore.Signal(Event)
    signal_strategy: QtCore.Signal = QtCore.Signal(Event)
    signal_popup: QtCore.Signal = QtCore.Signal(Event)

    def __init__(self, main_engine: MainEngine, event_engine: EventEngine) :
        super().__init__()

        self.main_engine: MainEngine = main_engine
        self.event_engine: EventEngine = event_engine
        self.cta_engine: CtaEngine = main_engine.get_engine(APP_NAME)

        self.managers: Dict[str, StrategyManager] = {}

        self.init_ui()
        self.register_event()
        self.cta_engine.init_engine()
        self.update_class_combo()
        #####################################################
        #self.cta_engine.init_all_strategies()
        #####################################################

    def init_ui(self) :
        self.setWindowTitle("CTA策略")
        # Create widgets
        self.class_combo: QtWidgets.QComboBox = QtWidgets.QComboBox()

        add_button: QtWidgets.QPushButton = QtWidgets.QPushButton("添加策略")
        add_button.clicked.connect(self.add_strategy)

        calc_button: QtWidgets.QPushButton = QtWidgets.QPushButton('资金试算')
        calc_button.clicked.connect(self.on_btn_calc)

        init_button: QtWidgets.QPushButton = QtWidgets.QPushButton("全部初始化")
        init_button.clicked.connect(self.cta_engine.init_all_strategies)

        start_button: QtWidgets.QPushButton = QtWidgets.QPushButton("全部启动")
        start_button.clicked.connect(self.cta_engine.start_all_strategies)

        stop_button: QtWidgets.QPushButton = QtWidgets.QPushButton("全部停止")
        stop_button.clicked.connect(self.cta_engine.stop_all_strategies)

        self.btn_auto_start: QtWidgets.QPushButton = QtWidgets.QPushButton()
        self.btn_auto_start.clicked.connect(self.onButton_auto_start)
        if self.cta_engine.strategy_setting['autostart'] == True :
            self.btn_auto_start.setText('全自动开启(已启用)')
            self.cta_engine.write_logfile('init_ui:autostart is True')
        else :
            self.btn_auto_start.setText('全自动开启(未启用)')
            self.cta_engine.write_logfile('init_ui:autostart is False')

        clear_button: QtWidgets.QPushButton = QtWidgets.QPushButton("清空日志")
        clear_button.clicked.connect(self.clear_log)

        roll_button: QtWidgets.QPushButton = QtWidgets.QPushButton("移仓助手")
        roll_button.clicked.connect(self.roll)

        self.scroll_layout: QtWidgets.QVBoxLayout = QtWidgets.QVBoxLayout()
        self.scroll_layout.addStretch()

        scroll_widget: QtWidgets.QWidget = QtWidgets.QWidget()
        scroll_widget.setLayout(self.scroll_layout)

        self.scroll_area: QtWidgets.QScrollArea = QtWidgets.QScrollArea()
        self.scroll_area.setWidgetResizable(True)
        self.scroll_area.setWidget(scroll_widget)

        self.log_monitor: CtaLogMonitor = CtaLogMonitor(self.main_engine, self.event_engine)

        self.stop_order_monitor: StopOrderMonitor = StopOrderMonitor(
            self.main_engine, self.event_engine
        )

        self.strategy_combo = QtWidgets.QComboBox()
        self.strategy_combo.setMinimumWidth(200)
        find_button = QtWidgets.QPushButton("查找")
        find_button.clicked.connect(self.find_strategy)

        # Set layout
        hbox1: QtWidgets.QHBoxLayout = QtWidgets.QHBoxLayout()
        hbox1.addWidget(self.class_combo)
        hbox1.addWidget(add_button)
        hbox1.addStretch()
        hbox1.addWidget(self.strategy_combo)
        hbox1.addWidget(find_button)
        hbox1.addStretch()
        hbox1.addWidget(init_button)
        hbox1.addWidget(start_button)
        hbox1.addWidget(stop_button)
        #hbox1.addWidget(self.btn_auto_start)
        hbox1.addWidget(clear_button)
        #hbox1.addWidget(roll_button)

        grid: QtWidgets.QGridLayout = QtWidgets.QGridLayout()
        grid.addWidget(self.scroll_area, 0, 0, 2, 1)
        grid.addWidget(self.stop_order_monitor, 0, 1)
        grid.addWidget(self.log_monitor, 1, 1)

        vbox: QtWidgets.QVBoxLayout = QtWidgets.QVBoxLayout()
        vbox.addLayout(hbox1)
        vbox.addLayout(grid)

        self.setLayout(vbox)

    def onButton_auto_start(self) :
        if self.cta_engine.strategy_setting['autostart'] == True :
            self.cta_engine.strategy_setting['autostart'] = False
            self.btn_auto_start.setText('全自动开启(未启用)')
            self.cta_engine.write_logfile('onButton_auto_start:set autostart False')
        else :
            self.cta_engine.strategy_setting['autostart'] = True
            self.btn_auto_start.setText('全自动开启(已启用)')
            self.cta_engine.write_logfile('onButton_auto_start:set autostart True')

        self.cta_engine.set_autostart_all_strategies()
        self.cta_engine.save_strategy_setting()

    def update_class_combo(self) :
        names = self.cta_engine.get_all_strategy_class_names()
        names.sort()
        self.class_combo.addItems(names)

    def update_strategy_combo(self) :
        names = list(self.managers.keys())
        names.sort()
        self.strategy_combo.clear()
        self.strategy_combo.addItems(names)

    def register_event(self) :
        self.signal_strategy.connect(self.process_strategy_event)
        self.event_engine.register(EVENT_CTA_STRATEGY, self.signal_strategy.emit)
        #########################################
        self.signal_popup.connect(self.process_popup_event)
        self.event_engine.register(EVENT_POPUP, self.signal_popup.emit )
        #########################################

    def process_popup_event(self, event) :
        sinfoDlg = sInfoDialog(event.data['title'], event.data['content'])
        sinfoDlg.exec_()

    def process_strategy_event(self, event) :
        """
        Update strategy status onto its monitor.
        """
        data = event.data
        strategy_name: str = data["strategy_name"]

        if strategy_name in self.managers :
            manager: StrategyManager = self.managers[strategy_name]
            manager.update_data(data)
        else :
            manager: StrategyManager = StrategyManager(self, self.cta_engine, data)
            self.scroll_layout.insertWidget(0, manager)
            self.managers[strategy_name] = manager
            self.update_strategy_combo()

    def remove_strategy(self, strategy_name) :
        manager: StrategyManager = self.managers.pop(strategy_name)
        manager.deleteLater()
        self.update_strategy_combo()

    def add_strategy(self) :
        class_name: str = str(self.class_combo.currentText())
        if not class_name:
            return

        parameters: dict = self.cta_engine.get_strategy_class_parameters(class_name)
        editor: AddStrategyEditor = AddStrategyEditor(parameters, class_name=class_name)
        n: int = editor.exec_()

        if n == editor.DialogCode.Accepted :
            setting: dict = editor.get_setting()
            ########################################
            ssymbol: str = setting.pop("symbol")
            ssym = re.match('[a-zA-Z]+', ssymbol)
            if ssym == None :
                self.cta_engine.write_log('symbol[{}] is not exist, please check'.format(ssymbol) )
                return
            scont = self.main_engine.get_contract(ssym[0])
            if scont == None :
                self.cta_engine.write_log('contract[{}] cfg is not exist, please add'.format(ssym[0]) )
                return
            vt_symbol = ssymbol + '.' + scont.exchange.value
            ########################################
            strategy_name: str = setting.pop("strategy_name")
            ########################################
            self.cta_engine.add_strategy(class_name, strategy_name, vt_symbol, setting)
            #self.cta_engine.init_strategy(strategy_name)

    def on_btn_calc(self) :
        editor = CalcEditor()
        n: int = editor.exec_()

    def find_strategy(self) :
        strategy_name = self.strategy_combo.currentText()
        manager = self.managers[strategy_name]
        self.scroll_area.ensureWidgetVisible(manager)

    def clear_log(self) :
        self.log_monitor.setRowCount(0)

    def show(self) :
        self.showMaximized()

    def roll(self) :
        dialog: RolloverTool = RolloverTool(self)
        dialog.exec_()

class StrategyManager(QtWidgets.QFrame) :
    """
    Manager for a strategy
    """
    def __init__(
        self, cta_manager: CtaManager, cta_engine: CtaEngine, data: dict
    ) :
        super(StrategyManager, self).__init__()

        self.cta_manager: CtaManager = cta_manager
        self.cta_engine: CtaEngine = cta_engine

        self.strategy_name: str = data["strategy_name"]
        self._data: dict = data

        self.init_ui()

    def init_ui(self) :
        self.setFixedHeight(300)
        self.setFrameShape(self.Shape.Box)
        self.setLineWidth(1)

        self.init_button: QtWidgets.QPushButton = QtWidgets.QPushButton("初始化")
        self.init_button.clicked.connect(self.init_strategy)

        self.start_button: QtWidgets.QPushButton = QtWidgets.QPushButton("启动")
        self.start_button.clicked.connect(self.start_strategy)
        self.start_button.setEnabled(False)

        self.stop_button: QtWidgets.QPushButton = QtWidgets.QPushButton("停止")
        self.stop_button.clicked.connect(self.stop_strategy)
        self.stop_button.setEnabled(False)

        self.auto_start_button: QtWidgets.QPushButton = QtWidgets.QPushButton()
        self.auto_start_button.clicked.connect(self.auto_start_strategy)
        self.auto_start_button.setEnabled(True)
        self.update_auto_start_button()

        self.edit_button: QtWidgets.QPushButton = QtWidgets.QPushButton("编辑")
        self.edit_button.clicked.connect(self.edit_strategy)
        if self._data['class_name'] == 'run_example' :
            if SETTINGS.get('userMode', None) != 'devTest' :
                self.edit_button.setEnabled(False)

        self.pos0_run_button: QtWidgets.QPushButton = QtWidgets.QPushButton()
        self.pos0_run_button.clicked.connect(self.pos0_run_strategy)
        self.pos0_run_button.setEnabled(True)
        self.update_pos0_run_button()

        self.remove_button: QtWidgets.QPushButton = QtWidgets.QPushButton("移除")
        self.remove_button.clicked.connect(self.remove_strategy)

        strategy_name: str = self._data["strategy_name"]
        vt_symbol: str = self._data["vt_symbol"]
        ssymbol: str = self._data["symbol"]
        class_name: str = self._data["class_name"]
        author: str = self._data["author"]

        label_text = '{} - {} ({})'.format(
                          strategy_name, ssymbol, class_name )
        if self._data['class_name'] == 'run_example' :
            label_text = '{} - {} - {} ({})'.format(
                    strategy_name, ssymbol,
                    self._data['parameters'].get('target_symbol', ''),
                    class_name )
        label: QtWidgets.QLabel = QtWidgets.QLabel(label_text)
        label.setAlignment(QtCore.Qt.AlignCenter)

        self.parameters_monitor: ParametersMonitor = ParametersMonitor(self._data)
        svar = copy.deepcopy( self._data["variables"] )
        svar.pop('inited')
        svar.pop('trading')
        #self.variables_monitor: DataMonitor = DataMonitor(self._data["variables"])
        self.variables_monitor: DataMonitor = DataMonitor(svar)

        hbox: QtWidgets.QHBoxLayout = QtWidgets.QHBoxLayout()
        hbox.addWidget(self.init_button)
        hbox.addWidget(self.start_button)
        hbox.addWidget(self.stop_button)
        #hbox.addWidget(self.auto_start_button)
        hbox.addWidget(self.edit_button)
        #hbox.addWidget(self.pos0_run_button)
        hbox.addWidget(self.remove_button)

        vbox: QtWidgets.QVBoxLayout = QtWidgets.QVBoxLayout()
        vbox.addWidget(label)
        vbox.addLayout(hbox)
        vbox.addWidget(self.parameters_monitor)
        vbox.addWidget(self.variables_monitor)
        self.setLayout(vbox)

    def update_auto_start_button(self) :
        if self._data['autostart'] == True :
            self.auto_start_button.setText('自动开启(已启用)')
            self.cta_engine.write_logfile('init_ui:strag[{}],symbol[{}],autostart is True'.format(
                                          self._data['strategy_name'], self._data['symbol']) )
        else :
            self.auto_start_button.setText('自动开启(未启用)')
            self.cta_engine.write_logfile('init_ui:strag[{}],symbol[{}],autostart is False'.format(
                                          self._data['strategy_name'], self._data['symbol']) )

    def update_pos0_run_button(self) :
        if self._data['pos0_run'] == True :
            self.pos0_run_button.setText('仓位0继续运行')
            self.cta_engine.write_logfile('init_ui:strag[{}],symbol[{}],pos0_run is True'.format(
                                          self._data['strategy_name'], self._data['symbol']) )
        else :
            self.pos0_run_button.setText('仓位0停止运行')
            self.cta_engine.write_logfile('init_ui:strag[{}],symbol[{}],pos0_run is False'.format(
                                          self._data['strategy_name'], self._data['symbol']) )

    def update_data(self, data: dict) :
        self._data = data

        self.parameters_monitor.update_data(data["parameters"])
        svar = copy.deepcopy( self._data["variables"] )
        svar.pop('inited')
        svar.pop('trading')
        #self.variables_monitor.update_data(data["variables"])
        self.variables_monitor.update_data(svar)

        # Update button status
        variables: list = data["variables"]
        inited: bool = variables["inited"]
        trading: bool = variables["trading"]
        ############################################
        self.update_auto_start_button()
        self.update_pos0_run_button()
        ############################################
        if not inited :
            return
        self.init_button.setEnabled(False)

        if trading:
            self.start_button.setEnabled(False)
            self.stop_button.setEnabled(True)
            self.edit_button.setEnabled(False)
            self.remove_button.setEnabled(False)
        else:
            self.start_button.setEnabled(True)
            self.stop_button.setEnabled(False)
            if self._data['class_name'] == 'run_example' :
                if SETTINGS.get('userMode', None) == 'devTest' :
                    self.edit_button.setEnabled(True)
            else :
                self.edit_button.setEnabled(True)
            self.remove_button.setEnabled(True)

    def init_strategy(self) :
        self.cta_engine.init_strategy(self.strategy_name)

    def start_strategy(self) :
        self.cta_engine.start_strategy(self.strategy_name)

    def stop_strategy(self) :
        self.cta_engine.stop_strategy(self.strategy_name)

    def auto_start_strategy(self) :
        self.cta_engine.auto_start_strategy(self.strategy_name)

    def pos0_run_strategy(self) :
        self.cta_engine.pos0_run_strategy(self.strategy_name)

    def edit_strategy(self) :
        strategy_name: str = self._data["strategy_name"]

        parameters: dict = self.cta_engine.get_strategy_parameters(strategy_name)
        editor: SettingEditor = SettingEditor(parameters, strategy_name=strategy_name)
        n: int = editor.exec_()

        if n == editor.DialogCode.Accepted :
            setting: dict = editor.get_setting()
            self.cta_engine.edit_strategy(strategy_name, setting)

    def remove_strategy(self) :
        sconfirm = ConfirmDialog('确定要删除策略[{}]吗?\n删除后不可恢复!'.format(self.strategy_name) )
        n: int = sconfirm.exec_()
        if n == sconfirm.DialogCode.Accepted :
            result: bool = self.cta_engine.remove_strategy(self.strategy_name)
            if result :
                self.cta_manager.remove_strategy(self.strategy_name)

class ParametersMonitor(QtWidgets.QTableWidget) :
    def __init__(self, data: dict) :
        super(ParametersMonitor, self).__init__()

        self._data = data
        self.cells: dict = {}

        self.init_ui()

    def init_ui(self) :
        labels: list = self._data['parameters_nm']
        self.setColumnCount(len(labels))
        self.setHorizontalHeaderLabels(labels)

        self.setRowCount(1)
        self.verticalHeader().setSectionResizeMode(
            QtWidgets.QHeaderView.Stretch
        )
        self.verticalHeader().setVisible(False)
        self.setEditTriggers(self.EditTrigger.NoEditTriggers)

        for column, name in enumerate(self._data['parameters'].keys()):
            value = self._data['parameters'][name]
            if name in ['sbs1', 'sbs2'] :
                if value == 0 :
                    value = '买入'
                elif value == 1 :
                    value = '卖出'
            elif name == 'slargeless' :
                if value == 0 :
                    value = '大于'
                elif value == 1 :
                    value = '小于'
            elif name == 'sbs' :
                if value == 0 :
                    value = '买入'
                elif value == 1 :
                    value = '卖出'

            cell: QtWidgets.QTableWidgetItem = QtWidgets.QTableWidgetItem(str(value))
            cell.setTextAlignment(QtCore.Qt.AlignCenter)

            self.setItem(0, column, cell)
            self.cells[name] = cell

    def update_data(self, data: dict) :
        for name, value in data.items():
            if name in ['sbs1', 'sbs2'] :
                if value == 0 :
                    value = '买入'
                elif value == 1 :
                    value = '卖出'
            elif name == 'slargeless' :
                if value == 0 :
                    value = '大于'
                elif value == 1 :
                    value = '小于'
            elif name == 'sbs' :
                if value == 0 :
                    value = '买入'
                elif value == 1 :
                    value = '卖出'
            cell: QtWidgets.QTableWidgetItem = self.cells[name]
            cell.setText(str(value))

class DataMonitor(QtWidgets.QTableWidget) :
    """
    Table monitor for parameters and variables.
    """
    def __init__(self, data: dict) :
        super(DataMonitor, self).__init__()

        self._data: dict = data
        self.cells: dict = {}

        self.init_ui()

    def init_ui(self) :
        labels: list = list(self._data.keys())
        self.setColumnCount(len(labels))
        self.setHorizontalHeaderLabels(labels)

        self.setRowCount(1)
        self.verticalHeader().setSectionResizeMode(
            QtWidgets.QHeaderView.Stretch
        )
        self.verticalHeader().setVisible(False)
        self.setEditTriggers(self.EditTrigger.NoEditTriggers)

        for column, name in enumerate(self._data.keys()):
            value = self._data[name]

            cell: QtWidgets.QTableWidgetItem = QtWidgets.QTableWidgetItem(str(value))
            cell.setTextAlignment(QtCore.Qt.AlignCenter)

            self.setItem(0, column, cell)
            self.cells[name] = cell

    def update_data(self, data: dict) :
        for name, value in data.items():
            cell: QtWidgets.QTableWidgetItem = self.cells.get(name, None)
            if cell :
                cell.setText(str(value))

class StopOrderMonitor(BaseMonitor):
    """
    Monitor for local stop order.
    """
    event_type: str = EVENT_CTA_STOPORDER
    data_key: str = "stop_orderid"
    sorting: bool = True

    headers: dict = {
        "stop_orderid": {
            "display": "停止委托号",
            "cell": BaseCell,
            "update": False,
        },
        "vt_orderids": {"display": "限价委托号", "cell": BaseCell, "update": True},
        "vt_symbol": {"display": "本地代码", "cell": BaseCell, "update": False},
        "direction": {"display": "方向", "cell": EnumCell, "update": False},
        "offset": {"display": "开平", "cell": EnumCell, "update": False},
        "price": {"display": "价格", "cell": BaseCell, "update": False},
        "volume": {"display": "数量", "cell": BaseCell, "update": False},
        "status": {"display": "状态", "cell": EnumCell, "update": True},
        "datetime": {"display": "时间", "cell": TimeCell, "update": False},
        "lock": {"display": "锁仓", "cell": BaseCell, "update": False},
        "net": {"display": "净仓", "cell": BaseCell, "update": False},
        "strategy_name": {"display": "策略名", "cell": BaseCell, "update": False},
    }

    def __del__(self) :
        pass

class CtaLogMonitor(BaseMonitor) :
    """
    Monitor for log data.
    """
    event_type: str = EVENT_CTA_LOG
    data_key: str = ""
    sorting: bool = False

    headers: dict = {
        "time": {"display": "时间", "cell": TimeCell, "update": False},
        "msg": {"display": "信息", "cell": MsgCell, "update": False},
    }

    def init_ui(self) :
        self.numrow_remove = 6000
        super(CtaLogMonitor, self).init_ui()
        #self.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch)
        self.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)

    def insert_new_row(self, data) :
        ########################################################
        if self.rowCount() > self.numrow_remove :
            num_rmv = math.floor( self.numrow_remove/2 )
            for i in range(num_rmv) :
                self.removeRow(num_rmv)
        ########################################################
        super(CtaLogMonitor, self).insert_new_row(data)
        #self.resizeRowToContents(0)
        #self.resizeColumnsToContents() #不能用,会导致性能问题
        ########################################################

class SettingEditor(QtWidgets.QDialog):
    """
    For creating new strategy and editing strategy parameters.
    """
    def __init__(
        self, parameters: dict, strategy_name: str = "", class_name: str = ""
    ) :
        super(SettingEditor, self).__init__()

        self.parameters: dict = parameters
        self.strategy_name: str = strategy_name
        self.class_name: str = class_name

        self.edits: dict = {}

        self.init_ui()

    def init_ui(self) :
        form: QtWidgets.QFormLayout = QtWidgets.QFormLayout()

        # Add symbol and name edit if add new strategy
        if self.class_name:
            self.setWindowTitle(f"添加策略：{self.class_name}")
            button_text: str = "添加"
            parameters: dict = {"strategy_name": "", "symbol": ""}
            parameters.update(self.parameters['parameters'])
        else:
            self.setWindowTitle(f"参数编辑：{self.strategy_name}")
            button_text: str = "确定"
            parameters: dict = self.parameters['parameters']

        for name, value in parameters.items():
            type_: type = type(value)

            edit: QtWidgets.QLineEdit = QtWidgets.QLineEdit(str(value))
            if type_ is int:
                validator: QtGui.QIntValidator = QtGui.QIntValidator()
                edit.setValidator(validator)
            elif type_ is float:
                validator: QtGui.QDoubleValidator = QtGui.QDoubleValidator()
                edit.setValidator(validator)

            form.addRow('{} {}'.format(
                        self.parameters['parameters_nm'].get(name,name), type_),
                        edit)

            self.edits[name] = (edit, type_)

        button: QtWidgets.QPushButton = QtWidgets.QPushButton(button_text)
        button.clicked.connect(self.accept)
        form.addRow(button)

        widget: QtWidgets.QWidget = QtWidgets.QWidget()
        widget.setLayout(form)

        scroll: QtWidgets.QScrollArea = QtWidgets.QScrollArea()
        scroll.setWidgetResizable(True)
        scroll.setWidget(widget)

        vbox: QtWidgets.QVBoxLayout = QtWidgets.QVBoxLayout()
        vbox.addWidget(scroll)
        self.setLayout(vbox)

    def get_setting(self) -> dict:
        setting: dict = {}

        if self.class_name:
            setting["class_name"] = self.class_name

        for name, tp in self.edits.items():
            edit, type_ = tp
            value_text = edit.text()

            if type_ == bool:
                if value_text == "True":
                    value = True
                else:
                    value = False
            else:
                value = type_(value_text)

            setting[name] = value

        return setting

class AddStrategyEditor(QtWidgets.QDialog) :
    """
    For creating new strategy and editing strategy parameters.
    """
    def __init__(self, parameters: dict, class_name: str = "") :
        super(AddStrategyEditor, self).__init__()

        self.parameters: dict = parameters
        self.class_name: str = class_name

        self.edits: dict = {}

        self.init_ui()

    def init_ui(self) :
        form: QtWidgets.QFormLayout = QtWidgets.QFormLayout()

        self.setWindowTitle(f"添加策略：{self.class_name}")
        button_text: str = '添加'
        parameters: dict = {'strategy_name': '', 'symbol': ''}
        parameters.update(self.parameters['parameters'])

        for name, value in parameters.items():
            type_: type = type(value)

            edit: QtWidgets.QLineEdit = QtWidgets.QLineEdit(str(value))
            if name in ['sbs1', 'sbs2'] :
                edit: QtWidgets.QComboBox = QtWidgets.QComboBox()
                edit.addItems(['买入', '卖出'])
                edit.setCurrentIndex(0)
            elif name == 'slargeless' :
                edit: QtWidgets.QComboBox = QtWidgets.QComboBox()
                edit.addItems(['大于', '小于'])
                edit.setCurrentIndex(0)
            elif name == 'sbs' :
                edit: QtWidgets.QComboBox = QtWidgets.QComboBox()
                edit.addItems(['买入', '卖出'])
                edit.setCurrentIndex(0)
            else :
                if type_ is int:
                    validator: QtGui.QIntValidator = QtGui.QIntValidator()
                    edit.setValidator(validator)
                elif type_ is float:
                    validator: QtGui.QDoubleValidator = QtGui.QDoubleValidator()
                    edit.setValidator(validator)

            form.addRow('{} {}'.format(
                        self.parameters['parameters_nm'].get(name,name), type_),
                        edit)

            self.edits[name] = (edit, type_)

        button: QtWidgets.QPushButton = QtWidgets.QPushButton(button_text)
        #button.clicked.connect(self.accept)
        button.clicked.connect(self.btnClicked)
        form.addRow(button)

        widget: QtWidgets.QWidget = QtWidgets.QWidget()
        widget.setLayout(form)

        scroll: QtWidgets.QScrollArea = QtWidgets.QScrollArea()
        scroll.setWidgetResizable(True)
        scroll.setWidget(widget)

        vbox: QtWidgets.QVBoxLayout = QtWidgets.QVBoxLayout()
        vbox.addWidget(scroll)
        self.setLayout(vbox)

    def get_setting(self) -> dict:
        setting: dict = {}

        if self.class_name:
            setting["class_name"] = self.class_name

        for name, tp in self.edits.items():
            edit, type_ = tp
            value_text = ''
            if name in ['sbs1', 'sbs2']:
                value_text = edit.currentIndex()
            elif name == 'slargeless' :
                value_text = edit.currentIndex()
            elif name == 'sbs' :
                value_text = edit.currentIndex()
            else :
                value_text = edit.text()

            if type_ == bool:
                if value_text == "True":
                    value = True
                else:
                    value = False
            else:
                value = type_(value_text)

            setting[name] = value

        return setting

    def btnClicked(self) :
        if self.class_name == 'tGrid' :
            sset = self.get_setting()
            sconfirm = ConfirmDialog('symbol[{}],init_price[{}]的值影响非常大!!!!!!\n'
                                     '请再次检查后,确定要继续添加吗?'.format(
                                     sset['symbol'], sset['init_price'] ) )
            n: int = sconfirm.exec_()
            if n == sconfirm.DialogCode.Accepted :
                self.accept()
        else :
            self.accept()

class CalcEditor(QtWidgets.QDialog):
    def __init__(self) :
        super(CalcEditor, self).__init__()
        self.edits: dict = {}
        self.sres1: dict = {}
        self.sres: dict = {}
        self.init_ui()

    def init_ui(self) :
        self.setWindowTitle('资金试算')
        button_text: str = '计算'
        form: QtWidgets.QFormLayout = QtWidgets.QFormLayout()
        ############################################
        parameters = {
            'init_pos'    : 0,
            'init_price'  : 3000.0,
            'buy_length'  : 10.0,
            'grid_lots'   : 1,
            '合约规模'    : 10,
            '保证金率(%)' : 10.0,
            '试算价格'    : 2000.0,
        }
        for name, value in parameters.items() :
            type_: type = type(value)
            edit: QtWidgets.QLineEdit = QtWidgets.QLineEdit(str(value))
            if type_ is int:
                validator: QtGui.QIntValidator = QtGui.QIntValidator()
                edit.setValidator(validator)
            elif type_ is float:
                validator: QtGui.QDoubleValidator = QtGui.QDoubleValidator()
                edit.setValidator(validator)
            form.addRow(f"{name} {type_}", edit)
            self.edits[name] = (edit, type_)
        ############################################
        form.addRow( QtWidgets.QLabel('所需最大资金信息:') )
        sresults = {
            'grid_price'  : 0.0,
            'grid_idx'    : 0,
            'total_pos'   : 0,
            '持仓保证金'  : 0.0,
            '持仓损益'    : 0.0,
            '所需资金'    : 0.0,
        }
        for name, value in sresults.items() :
            type_: type = type(value)
            edit: QtWidgets.QLineEdit = QtWidgets.QLineEdit(str(value))
            if type_ is int:
                validator: QtGui.QIntValidator = QtGui.QIntValidator()
                edit.setValidator(validator)
            elif type_ is float:
                validator: QtGui.QDoubleValidator = QtGui.QDoubleValidator()
                edit.setValidator(validator)
            edit.setEnabled(False)
            form.addRow(f"{name} {type_}", edit)
            self.sres[name] = (edit, type_)
        ############################################
        form2: QtWidgets.QFormLayout = QtWidgets.QFormLayout()
        form2.addRow( QtWidgets.QLabel('试算所需资金信息:') )
        sresults = {
            'grid_price'  : 0.0,
            'grid_idx'    : 0,
            'total_pos'   : 0,
            '持仓保证金'  : 0.0,
            '持仓损益'    : 0.0,
            '所需资金'    : 0.0,
        }
        for name, value in sresults.items() :
            type_: type = type(value)
            edit: QtWidgets.QLineEdit = QtWidgets.QLineEdit(str(value))
            if type_ is int:
                validator: QtGui.QIntValidator = QtGui.QIntValidator()
                edit.setValidator(validator)
            elif type_ is float:
                validator: QtGui.QDoubleValidator = QtGui.QDoubleValidator()
                edit.setValidator(validator)
            edit.setEnabled(False)
            form2.addRow(f"{name} {type_}", edit)
            self.sres1[name] = (edit, type_)
        ############################################
        button: QtWidgets.QPushButton = QtWidgets.QPushButton(button_text)
        button.clicked.connect(self.btnClicked)
        form.addRow(button)

        hbox = QtWidgets.QHBoxLayout()
        hbox.addLayout(form)
        hbox.addLayout(form2)
        self.setLayout(hbox)

    def get_setting(self) -> dict:
        setting: dict = {}
        for name, tp in self.edits.items():
            edit, type_ = tp
            value_text = edit.text()

            if type_ == bool:
                if value_text == "True":
                    value = True
                else:
                    value = False
            else:
                value = type_(value_text)

            setting[name] = value

        return setting

    def btnClicked(self) :
        sset = self.get_setting()
        ################################
        calcPrice = sset['试算价格']
        calcGrid = None
        ################################
        sgrids = []
        grid_idx = 0
        grid_price = sset['init_price']
        grid_pos = sset['init_pos']
        grid_depo = grid_pos*grid_price*sset['合约规模']*sset['保证金率(%)']/100.0
        grid_pnl = 0
        grid_amt = grid_depo - grid_pnl
        sgrids.append([
            grid_idx,
            grid_price,
            grid_pos,
            grid_depo,
            grid_pnl,
            grid_amt,
            ])
        while True :
            ###########################
            last_grid_idx = grid_idx
            last_grid_price = grid_price
            last_grid_pos = grid_pos
            last_grid_pnl = grid_pnl
            ###########################
            grid_idx = last_grid_idx - 1
            grid_price = last_grid_price - sset['buy_length']
            if grid_price < 0.0 :
                break
            grid_pos = last_grid_pos + sset['grid_lots']
            grid_depo = grid_pos*grid_price*sset['合约规模']*sset['保证金率(%)']/100.0
            grid_pnl = last_grid_pnl - last_grid_pos*sset['合约规模']*sset['buy_length']
            grid_amt = grid_depo - grid_pnl
            sgrids.append([
                grid_idx,
                grid_price,
                grid_pos,
                grid_depo,
                grid_pnl,
                grid_amt,
                ])
            ###########################
            if calcPrice<=last_grid_price and calcPrice>=grid_price :
                calcGrid = sgrids[-1]
        ################################################
        sgrids.sort(key=lambda x:x[5])
        ################################################
        samt = sgrids[-1]
        self.sres['grid_price'][0].setText('{}'.format(samt[1]) )
        self.sres['grid_idx'][0].setText('{}'.format(samt[0]) )
        self.sres['total_pos'][0].setText('{}'.format(samt[2]) )
        self.sres['持仓保证金'][0].setText('{}'.format(samt[3]) )
        self.sres['持仓损益'][0].setText('{}'.format(samt[4]) )
        self.sres['所需资金'][0].setText('{}'.format(samt[5]) )
        ################################################
        if calcGrid != None :
            self.sres1['grid_price'][0].setText('{}'.format(calcGrid[1]) )
            self.sres1['grid_idx'][0].setText('{}'.format(calcGrid[0]) )
            self.sres1['total_pos'][0].setText('{}'.format(calcGrid[2]) )
            self.sres1['持仓保证金'][0].setText('{}'.format(calcGrid[3]) )
            self.sres1['持仓损益'][0].setText('{}'.format(calcGrid[4]) )
            self.sres1['所需资金'][0].setText('{}'.format(calcGrid[5]) )
        ################################################


